//
// Created by YANHAI on 2020/4/10.
//

#include <iostream>
#include <cassert>

using namespace std;

// ============== 指向普通函数的指针 =====================
int test1_func1(int a)
{
    return a;
}

int test1_func2(int a, int b = 10)
{
    return a;
}

void test1()
{
    /**
     * 函数名字就是函数的地址，使用指针指向函数地址
     */
    typedef int (*func_type)(int);
    func_type p = test1_func1;

    // 虽然有默认值，但是不能转为int (*func_type)(int)类型，
    // test1_func2的类型依然是int (*func_type)(int,int)
//    func_type p2 = test1_func2;
    int a = p(10);
    assert(a == 10);
}

// ============ 指向模板函数的指针=====================
template<typename T>
T test2_func1(T a)
{
    return a;
}

void test2()
{
    /**
     * 模板函数，也是同理（其实模板函数就是生成了多个不同类型的同名函数，重载）
     */
    typedef int (*func_type)(int);
    func_type p = test2_func1;
    int a = p(10);
    assert(a == 10);
}

// =============== 指向类成员函数（非静态成员函数）的指针 ===================
class Test {
public:
    Test(int a) : a(a) {}

private:
    int func1(int b)
    {
        return a + b;
    }

    int func2(int b)
    {
        return a - b;
    }

    int func3(int b)
    {
        return a * b;
    }

public:
    /**
     * func_type 是指向成员函数的指针类型，一定要在前面加作用域，表示属于Test类
     */
    typedef int (Test::*func_type)(int);

    func_type func(const string &s)
    {
        func_type p = nullptr;
        if (s == "+")
            p = &Test::func1;   // C++规定，必须使用&取成员函数的地址, func1 func2 func3可以是private修饰的，
        else if (s == "-")
            p = &Test::func2;
        else if ( s == "*")
            p = &Test::func3;
        return p;
    }

private:
    int a;
};

void test3()
{
    Test t(10);
    auto p = t.func("+");
    // 不可以这样使用，因为p函数是属于Test类的，必须由某个Test类的对象来调用
    // 如果是 p(20)调用的话，那this是谁？
//    int r = p(20);

    // 必须指定调用p的对象，p是函数的地址，由于函数名称本身就是地址，函数的地址相当于二级指针，因此要*p解引用，才是函数名称
    int r = (t.*p)(20);
    assert(r == 30);
}

// ================== 指向类成员函数（静态成员函数）的指针 ========================
class Test2 {
public:
    Test2() = default;

private:
    static int func1(int a, int b)
    {
        return a+b;
    }

    static int func2(int a, int b)
    {
        return a - b;
    }

    static int func3(int a, int b)
    {
        return a * b;
    }

public:
    /**
     * func_type 是指向成员函数的指针类型
     */
    typedef int (*func_type)(int, int);

    func_type func(const string &s)
    {
        // 静态成员函数，4种方式都可以
        // Test2::func1
        // &Test2::func1;
        // func1;
        // & func1;
        func_type p = nullptr;
        if (s == "+")
            p = Test2::func1;
        else if (s == "-")
            p = func2;
        else if ( s == "*")
            p = &Test2::func3;
        return p;
    }
};

void test4()
{
    Test2 t;
    auto p = t.func("+");

    // 调用的时候，使用 (*p)()和 p() 都可以，C++风格和C风格都兼容
    int r = (*p)(10, 20);
    assert(r == 30);

    p = t.func("-");
    r = p(10, 20);
    assert(r == -10);

    p = t.func("*");
    r = p(10, 20);
    assert(r == 200);
}

int main()
{
    test1();
    test2();
    test3();
    test4();
    return 0;
}
